const PENDING = 'pengding';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  status = PENDING; // 当前promise的状态
  value = undefined; // 当前promise的值
  reason = undefined; // 当前promise如果失败 失败的原因
  successCallbacks = []; // 如果异步 那么将回调存入到对应回调库中
  rejectCallbacks = [];
  // promise 的构造函数接受一个执行器 这个执行器会立即执行
  constructor(executor) {
    // 这个执行器接收两个参数 第一个参数是执行成功 第二个是失败
    // 在执行器执行的过程中如果resolve执行 那么这个promise成功
    try {
      executor(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }
  // all方法接收一个数组作为参数
  // 例如['a', p1, p2, p3, 'b'] 其中p1p2p3是promise对象
  static all(array) {
    let count = 0;
    let results = []; // 声明一个结果数组 接收数组每一项的结果
    return new MyPromise((res, rej) => { // all方法返回一个新的promise对象
      function setData(index, value) { // 往results里面放值的函数
        count++; // 没放入一个值 处理过的数量加1
        results[index] = value; // results对应项设置好值
        if (count === array.length) { // 如果处理过值的总数已经等于array的长度 说明所有的值都处理完了 
          res(results); // 返回成功的结果
        }
      }
      for (let i = 0; i < array.length; i++) {
        if (array[i] instanceof MyPromise) { // 如果这一项是promise类型的
          array[i].then((val) => { // 那么等promise执行完 在then里面拿到执行结果再往results数组里放
            setData(i, val);
          }, reason => {
            rej(reason); // 如果有一项的promise出错了 直接rej
          });
        } else { // 如果是普通值 直接往数组里放
          setData(i, array[i]);
        }
      }
    })
  }

  // 静态resolve接收一个参数
  static resolve(value) {
    if (value instanceof MyPromise) return value; // 如果这个参数是promise对象 那么直接返回 
    return new MyPromise(resolve => resolve(value)); // 如果不是 用promise包裹后返回
  }

  // 成功调用resolve方法 接收一个参数作为这个promise的返回值存在promise对象中
  resolve = data => {
    // 一旦status状态不是pending 那么就不再执行 保证状态不可逆
    if (this.status !== PENDING) return;
    this.status = FULFILLED;
    this.value = data; // 将promise成功获得的数据存在value中
    // 判断成功回调函数库中是否用未执行的函数 有的话依次执行
    while (this.successCallbacks.length) {
      this.successCallbacks.shift()();
    }
  }
  // 同resolve
  reject = reason => {
    if (this.status !== PENDING) return;
    this.status = REJECTED;
    this.reason = reason;
    while (this.rejectCallbacks.length) this.rejectCallbacks.shift()();
  }
  // then方法 接收两个函数作为参数 第一个是成功的回调
  then = (successCallback, rejectCallback) => {
    successCallback = successCallback || (value => value);
    rejectCallback = rejectCallback || (reason => { throw reason });
    // then方法 返回的是一个新的promise对象 所以在执行then的时候 new一个新的promise
    // 同样的 这个新promise的执行器也会立即执行
    let promise2 = new MyPromise((resolve, reject) => {
      // 当执行到then方法时候 status已经是FULFILLED说明promise已经执行成功
      // 直接执行成功的回调 
      // 同时将成功回调的返回值传递给下一个promise的resolve方法
      setTimeout(() => {
        try {
          if (this.status === FULFILLED) {
            const thenReturnVal = successCallback(this.value);
            resolvePromise(promise2, thenReturnVal, resolve, reject);
          } else if (this.status === REJECTED) {
            const thenReturnVal = rejectCallback(this.reason);
            resolvePromise(promise2, thenReturnVal, resolve, reject);
          } else {
            this.successCallbacks.push(() => {
              try {
                const thenReturnVal = successCallback(this.value);
                resolvePromise(promise2, thenReturnVal, resolve, reject);
              } catch (error) {
                reject(error);
              }
            });
            this.rejectCallbacks.push(() => {
              try {
                const thenReturnVal = rejectCallback(this.reason);
                resolvePromise(promise2, thenReturnVal, resolve, reject);
              } catch (error) {
                reject(error);
              }
            })
          }
        } catch (error) {
          reject(error);
        }
      }, 0);
    });
    return promise2;
  }
  finally = callback => {
    // finally 也返回一个新的promise 在这个新promise的then方法里可以拿到最后成功或失败的值
    return this.then(value => { // 利用then方法可以直到最后是成功了还是失败了 无论成功还是失败都要执行callback
      // 如果callback的返回值是一个异步的promise 利用resolve静态方法包裹这个返回值
      // 例如 如果callback回调返回了 p3 而p3是一个延迟2秒执行的promise
      // 那么MyPromise.resolve(p3) === p3 也就是 p3.then。。。这样finally就会等这个promise执行完 才会调用then方法
      return MyPromise.resolve(callback()).then(() => value);
    }, reason => {
      // 同样的 如果callback的promise是失败的 那么执行抛出这个reason
      return MyPromise.resolve(callback()).then(() => { throw reason });
    }); // 调用then方法获取当前promise的状态
  }
  // promise中一旦某一处有错误发生 会因为then的特性一直传递下去 直到最后这个catch里
  catch = rejectCallback => {
    return this.then(undefined, rejectCallback);
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    reject(new TypeError('重复调用自己了哦~'));
  }
  if (x instanceof MyPromise) {
    // 是promise对象 那需要调用Promise的then方法判断这个promise是否成功
    // 如果成功 调用resolve方法 并且把值传递下去 如果失败 调用reject并且把原因传递下去
    x.then(value => resolve(value), reason => reject(reason));
    // x.then(resolve, reject);
  } else {
    resolve(x);
  }
}

const p1 = new MyPromise((resolve, reject) => {
  resolve('p1 complete');
})

const p2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2 complete');
  }, 1000);
})
const p3 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('p3 complete');
  }, 2000);
})

// let all = MyPromise.all(['a', p1, p2, p3, 'b']);

// all.then(value => {
//   console.log(value);
// }, reason => {
//   console.log(reason);
// })

// MyPromise.resolve(100).then(value => console.log(value));
// MyPromise.resolve(p2).then(value => console.log(value));

// p1.finally(() => {
//   console.log('finally');
//   return p3;
// }).then(val => console.log(val), reason => console.warn(reason));

p1
  .then(() => {
    console.log(66666)
    throw new Error('error');
  })
  .then(value => console.log(value))
  .catch(reason => {
    console.log(reason);
  });